home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / db.1.85.tar.gz / db.1.85.tar / db.1.85 / test / dbtest.c next >
C/C++ Source or Header  |  1994-09-01  |  17KB  |  754 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1992, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)dbtest.c    8.17 (Berkeley) 9/1/94";
  42. #endif /* not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/stat.h>
  46.  
  47. #include <ctype.h>
  48. #include <errno.h>
  49. #include <fcntl.h>
  50. #include <limits.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <unistd.h>
  55.  
  56. #include <db.h>
  57.  
  58. enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
  59.  
  60. void     compare __P((DBT *, DBT *));
  61. DBTYPE     dbtype __P((char *));
  62. void     dump __P((DB *, int));
  63. void     err __P((const char *, ...));
  64. void     get __P((DB *, DBT *));
  65. void     getdata __P((DB *, DBT *, DBT *));
  66. void     put __P((DB *, DBT *, DBT *));
  67. void     rem __P((DB *, DBT *));
  68. char    *sflags __P((int));
  69. void     synk __P((DB *));
  70. void    *rfile __P((char *, size_t *));
  71. void     seq __P((DB *, DBT *));
  72. u_int     setflags __P((char *));
  73. void    *setinfo __P((DBTYPE, char *));
  74. void     usage __P((void));
  75. void    *xmalloc __P((char *, size_t));
  76.  
  77. DBTYPE type;                /* Database type. */
  78. void *infop;                /* Iflags. */
  79. u_long lineno;                /* Current line in test script. */
  80. u_int flags;                /* Current DB flags. */
  81. int ofd = STDOUT_FILENO;        /* Standard output fd. */
  82.  
  83. DB *XXdbp;                /* Global for gdb. */
  84. int XXlineno;                /* Fast breakpoint for gdb. */
  85.  
  86. int
  87. main(argc, argv)
  88.     int argc;
  89.     char *argv[];
  90. {
  91.     extern int optind;
  92.     extern char *optarg;
  93.     enum S command, state;
  94.     DB *dbp;
  95.     DBT data, key, keydata;
  96.     size_t len;
  97.     int ch, oflags, sflag;
  98.     char *fname, *infoarg, *p, *t, buf[8 * 1024];
  99.  
  100.     infoarg = NULL;
  101.     fname = NULL;
  102.     oflags = O_CREAT | O_RDWR;
  103.     sflag = 0;
  104.     while ((ch = getopt(argc, argv, "f:i:lo:s")) != EOF)
  105.         switch (ch) {
  106.         case 'f':
  107.             fname = optarg;
  108.             break;
  109.         case 'i':
  110.             infoarg = optarg;
  111.             break;
  112.         case 'l':
  113.             oflags |= DB_LOCK;
  114.             break;
  115.         case 'o':
  116.             if ((ofd = open(optarg,
  117.                 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
  118.                 err("%s: %s", optarg, strerror(errno));
  119.             break;
  120.         case 's':
  121.             sflag = 1;
  122.             break;
  123.         case '?':
  124.         default:
  125.             usage();
  126.         }
  127.     argc -= optind;
  128.     argv += optind;
  129.  
  130.     if (argc != 2)
  131.         usage();
  132.  
  133.     /* Set the type. */
  134.     type = dbtype(*argv++);
  135.  
  136.     /* Open the descriptor file. */
  137.         if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
  138.         err("%s: %s", *argv, strerror(errno));
  139.  
  140.     /* Set up the db structure as necessary. */
  141.     if (infoarg == NULL)
  142.         infop = NULL;
  143.     else
  144.         for (p = strtok(infoarg, ",\t "); p != NULL;
  145.             p = strtok(0, ",\t "))
  146.             if (*p != '\0')
  147.                 infop = setinfo(type, p);
  148.  
  149.     /*
  150.      * Open the DB.  Delete any preexisting copy, you almost never
  151.      * want it around, and it often screws up tests.
  152.      */
  153.     if (fname == NULL) {
  154.         p = getenv("TMPDIR");
  155.         if (p == NULL)
  156.             p = "/var/tmp";
  157.         (void)sprintf(buf, "%s/__dbtest", p);
  158.         fname = buf;
  159.         (void)unlink(buf);
  160.     } else  if (!sflag)
  161.         (void)unlink(fname);
  162.  
  163.     if ((dbp = dbopen(fname,
  164.         oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
  165.         err("dbopen: %s", strerror(errno));
  166.     XXdbp = dbp;
  167.  
  168.     state = COMMAND;
  169.     for (lineno = 1;
  170.         (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
  171.         /* Delete the newline, displaying the key/data is easier. */
  172.         if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
  173.             *t = '\0';
  174.         if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#')
  175.             continue;
  176.  
  177.         /* Convenient gdb break point. */
  178.         if (XXlineno == lineno)
  179.             XXlineno = 1;
  180.         switch (*p) {
  181.         case 'c':            /* compare */
  182.             if (state != COMMAND)
  183.                 err("line %lu: not expecting command", lineno);
  184.             state = KEY;
  185.             command = COMPARE;
  186.             break;
  187.         case 'e':            /* echo */
  188.             if (state != COMMAND)
  189.                 err("line %lu: not expecting command", lineno);
  190.             /* Don't display the newline, if CR at EOL. */
  191.             if (p[len - 2] == '\r')
  192.                 --len;
  193.             if (write(ofd, p + 1, len - 1) != len - 1 ||
  194.                 write(ofd, "\n", 1) != 1)
  195.                 err("write: %s", strerror(errno));
  196.             break;
  197.         case 'g':            /* get */
  198.             if (state != COMMAND)
  199.                 err("line %lu: not expecting command", lineno);
  200.             state = KEY;
  201.             command = GET;
  202.             break;
  203.         case 'p':            /* put */
  204.             if (state != COMMAND)
  205.                 err("line %lu: not expecting command", lineno);
  206.             state = KEY;
  207.             command = PUT;
  208.             break;
  209.         case 'r':            /* remove */
  210.             if (state != COMMAND)
  211.                 err("line %lu: not expecting command", lineno);
  212.                         if (flags == R_CURSOR) {
  213.                 rem(dbp, &key);
  214.                 state = COMMAND;
  215.                         } else {
  216.                 state = KEY;
  217.                 command = REMOVE;
  218.             }
  219.             break;
  220.         case 'S':            /* sync */
  221.             if (state != COMMAND)
  222.                 err("line %lu: not expecting command", lineno);
  223.             synk(dbp);
  224.             state = COMMAND;
  225.             break;
  226.         case 's':            /* seq */
  227.             if (state != COMMAND)
  228.                 err("line %lu: not expecting command", lineno);
  229.             if (flags == R_CURSOR) {
  230.                 state = KEY;
  231.                 command = SEQ;
  232.             } else
  233.                 seq(dbp, &key);
  234.             break;
  235.         case 'f':
  236.             flags = setflags(p + 1);
  237.             break;
  238.         case 'D':            /* data file */
  239.             if (state != DATA)
  240.                 err("line %lu: not expecting data", lineno);
  241.             data.data = rfile(p + 1, &data.size);
  242.             goto ldata;
  243.         case 'd':            /* data */
  244.             if (state != DATA)
  245.                 err("line %lu: not expecting data", lineno);
  246.             data.data = xmalloc(p + 1, len - 1);
  247.             data.size = len - 1;
  248. ldata:            switch (command) {
  249.             case COMPARE:
  250.                 compare(&keydata, &data);
  251.                 break;
  252.             case PUT:
  253.                 put(dbp, &key, &data);
  254.                 break;
  255.             default:
  256.                 err("line %lu: command doesn't take data",
  257.                     lineno);
  258.             }
  259.             if (type != DB_RECNO)
  260.                 free(key.data);
  261.             free(data.data);
  262.             state = COMMAND;
  263.             break;
  264.         case 'K':            /* key file */
  265.             if (state != KEY)
  266.                 err("line %lu: not expecting a key", lineno);
  267.             if (type == DB_RECNO)
  268.                 err("line %lu: 'K' not available for recno",
  269.                     lineno);
  270.             key.data = rfile(p + 1, &key.size);
  271.             goto lkey;
  272.         case 'k':            /* key */
  273.             if (state != KEY)
  274.                 err("line %lu: not expecting a key", lineno);
  275.             if (type == DB_RECNO) {
  276.                 static recno_t recno;
  277.                 recno = atoi(p + 1);
  278.                 key.data = &recno;
  279.                 key.size = sizeof(recno);
  280.             } else {
  281.                 key.data = xmalloc(p + 1, len - 1);
  282.                 key.size = len - 1;
  283.             }
  284. lkey:            switch (command) {
  285.             case COMPARE:
  286.                 getdata(dbp, &key, &keydata);
  287.                 state = DATA;
  288.                 break;
  289.             case GET:
  290.                 get(dbp, &key);
  291.                 if (type != DB_RECNO)
  292.                     free(key.data);
  293.                 state = COMMAND;
  294.                 break;
  295.             case PUT:
  296.                 state = DATA;
  297.                 break;
  298.             case REMOVE:
  299.                 rem(dbp, &key);
  300.                 if ((type != DB_RECNO) && (flags != R_CURSOR))
  301.                     free(key.data);
  302.                 state = COMMAND;
  303.                 break;
  304.             case SEQ:
  305.                 seq(dbp, &key);
  306.                 if ((type != DB_RECNO) && (flags != R_CURSOR))
  307.                     free(key.data);
  308.                 state = COMMAND;
  309.                 break;
  310.             default:
  311.                 err("line %lu: command doesn't take a key",
  312.                     lineno);
  313.             }
  314.             break;
  315.         case 'o':
  316.             dump(dbp, p[1] == 'r');
  317.             break;
  318.         default:
  319.             err("line %lu: %s: unknown command character",
  320.                 lineno, p);
  321.         }
  322.     }
  323. #ifdef STATISTICS
  324.     /*
  325.      * -l must be used (DB_LOCK must be set) for this to be
  326.      * used, otherwise a page will be locked and it will fail.
  327.      */
  328.     if (type == DB_BTREE && oflags & DB_LOCK)
  329.         __bt_stat(dbp);
  330. #endif
  331.     if (dbp->close(dbp))
  332.         err("db->close: %s", strerror(errno));
  333.     (void)close(ofd);
  334.     exit(0);
  335. }
  336.  
  337. #define    NOOVERWRITE    "put failed, would overwrite key\n"
  338.  
  339. void
  340. compare(db1, db2)
  341.     DBT *db1, *db2;
  342. {
  343.     register size_t len;
  344.     register u_char *p1, *p2;
  345.  
  346.     if (db1->size != db2->size)
  347.         printf("compare failed: key->data len %lu != data len %lu\n",
  348.             db1->size, db2->size);
  349.  
  350.     len = MIN(db1->size, db2->size);
  351.     for (p1 = db1->data, p2 = db2->data; len--;)
  352.         if (*p1++ != *p2++) {
  353.             printf("compare failed at offset %d\n",
  354.                 p1 - (u_char *)db1->data);
  355.             break;
  356.         }
  357. }
  358.  
  359. void
  360. get(dbp, kp)
  361.     DB *dbp;
  362.     DBT *kp;
  363. {
  364.     DBT data;
  365.  
  366.     switch (dbp->get(dbp, kp, &data, flags)) {
  367.     case 0:
  368.         (void)write(ofd, data.data, data.size);
  369.         if (ofd == STDOUT_FILENO)
  370.             (void)write(ofd, "\n", 1);
  371.         break;
  372.     case -1:
  373.         err("line %lu: get: %s", lineno, strerror(errno));
  374.         /* NOTREACHED */
  375.     case 1:
  376. #define    NOSUCHKEY    "get failed, no such key\n"
  377.         if (ofd != STDOUT_FILENO)
  378.             (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
  379.         else
  380.             (void)fprintf(stderr, "%d: %.*s: %s",
  381.                 lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
  382. #undef    NOSUCHKEY
  383.         break;
  384.     }
  385. }
  386.  
  387. void
  388. getdata(dbp, kp, dp)
  389.     DB *dbp;
  390.     DBT *kp, *dp;
  391. {
  392.     switch (dbp->get(dbp, kp, dp, flags)) {
  393.     case 0:
  394.         return;
  395.     case -1:
  396.         err("line %lu: getdata: %s", lineno, strerror(errno));
  397.         /* NOTREACHED */
  398.     case 1:
  399.         err("line %lu: getdata failed, no such key", lineno);
  400.         /* NOTREACHED */
  401.     }
  402. }
  403.  
  404. void
  405. put(dbp, kp, dp)
  406.     DB *dbp;
  407.     DBT *kp, *dp;
  408. {
  409.     switch (dbp->put(dbp, kp, dp, flags)) {
  410.     case 0:
  411.         break;
  412.     case -1:
  413.         err("line %lu: put: %s", lineno, strerror(errno));
  414.         /* NOTREACHED */
  415.     case 1:
  416.         (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
  417.         break;
  418.     }
  419. }
  420.  
  421. void
  422. rem(dbp, kp)
  423.     DB *dbp;
  424.     DBT *kp;
  425. {
  426.     switch (dbp->del(dbp, kp, flags)) {
  427.     case 0:
  428.         break;
  429.     case -1:
  430.         err("line %lu: rem: %s", lineno, strerror(errno));
  431.         /* NOTREACHED */
  432.     case 1:
  433. #define    NOSUCHKEY    "rem failed, no such key\n"
  434.         if (ofd != STDOUT_FILENO)
  435.             (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
  436.         else if (flags != R_CURSOR)
  437.             (void)fprintf(stderr, "%d: %.*s: %s", 
  438.                 lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
  439.         else
  440.             (void)fprintf(stderr,
  441.                 "%d: rem of cursor failed\n", lineno);
  442. #undef    NOSUCHKEY
  443.         break;
  444.     }
  445. }
  446.  
  447. void
  448. synk(dbp)
  449.     DB *dbp;
  450. {
  451.     switch (dbp->sync(dbp, flags)) {
  452.     case 0:
  453.         break;
  454.     case -1:
  455.         err("line %lu: synk: %s", lineno, strerror(errno));
  456.         /* NOTREACHED */
  457.     }
  458. }
  459.  
  460. void
  461. seq(dbp, kp)
  462.     DB *dbp;
  463.     DBT *kp;
  464. {
  465.     DBT data;
  466.  
  467.     switch (dbp->seq(dbp, kp, &data, flags)) {
  468.     case 0:
  469.         (void)write(ofd, data.data, data.size);
  470.         if (ofd == STDOUT_FILENO)
  471.             (void)write(ofd, "\n", 1);
  472.         break;
  473.     case -1:
  474.         err("line %lu: seq: %s", lineno, strerror(errno));
  475.         /* NOTREACHED */
  476.     case 1:
  477. #define    NOSUCHKEY    "seq failed, no such key\n"
  478.         if (ofd != STDOUT_FILENO)
  479.             (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
  480.         else if (flags == R_CURSOR)
  481.             (void)fprintf(stderr, "%d: %.*s: %s", 
  482.                 lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
  483.         else
  484.             (void)fprintf(stderr,
  485.                 "%d: seq (%s) failed\n", lineno, sflags(flags));
  486. #undef    NOSUCHKEY
  487.         break;
  488.     }
  489. }
  490.  
  491. void
  492. dump(dbp, rev)
  493.     DB *dbp;
  494.     int rev;
  495. {
  496.     DBT key, data;
  497.     int flags, nflags;
  498.  
  499.     if (rev) {
  500.         flags = R_LAST;
  501.         nflags = R_PREV;
  502.     } else {
  503.         flags = R_FIRST;
  504.         nflags = R_NEXT;
  505.     }
  506.     for (;; flags = nflags)
  507.         switch (dbp->seq(dbp, &key, &data, flags)) {
  508.         case 0:
  509.             (void)write(ofd, data.data, data.size);
  510.             if (ofd == STDOUT_FILENO)
  511.                 (void)write(ofd, "\n", 1);
  512.             break;
  513.         case 1:
  514.             goto done;
  515.         case -1:
  516.             err("line %lu: (dump) seq: %s",
  517.                 lineno, strerror(errno));
  518.             /* NOTREACHED */
  519.         }
  520. done:    return;
  521. }
  522.     
  523. u_int
  524. setflags(s)
  525.     char *s;
  526. {
  527.     char *p, *index();
  528.  
  529.     for (; isspace(*s); ++s);
  530.     if (*s == '\n' || *s == '\0')
  531.         return (0);
  532.     if ((p = index(s, '\n')) != NULL)
  533.         *p = '\0';
  534.     if (!strcmp(s, "R_CURSOR"))        return (R_CURSOR);
  535.     if (!strcmp(s, "R_FIRST"))        return (R_FIRST);
  536.     if (!strcmp(s, "R_IAFTER"))         return (R_IAFTER);
  537.     if (!strcmp(s, "R_IBEFORE"))         return (R_IBEFORE);
  538.     if (!strcmp(s, "R_LAST"))         return (R_LAST);
  539.     if (!strcmp(s, "R_NEXT"))         return (R_NEXT);
  540.     if (!strcmp(s, "R_NOOVERWRITE"))    return (R_NOOVERWRITE);
  541.     if (!strcmp(s, "R_PREV"))        return (R_PREV);
  542.     if (!strcmp(s, "R_SETCURSOR"))        return (R_SETCURSOR);
  543.  
  544.     err("line %lu: %s: unknown flag", lineno, s);
  545.     /* NOTREACHED */
  546. }
  547.  
  548. char *
  549. sflags(flags)
  550.     int flags;
  551. {
  552.     switch (flags) {
  553.     case R_CURSOR:        return ("R_CURSOR");
  554.     case R_FIRST:        return ("R_FIRST");
  555.     case R_IAFTER:        return ("R_IAFTER");
  556.     case R_IBEFORE:        return ("R_IBEFORE");
  557.     case R_LAST:        return ("R_LAST");
  558.     case R_NEXT:        return ("R_NEXT");
  559.     case R_NOOVERWRITE:    return ("R_NOOVERWRITE");
  560.     case R_PREV:        return ("R_PREV");
  561.     case R_SETCURSOR:    return ("R_SETCURSOR");
  562.     }
  563.  
  564.     return ("UNKNOWN!");
  565. }
  566.     
  567. DBTYPE
  568. dbtype(s)
  569.     char *s;
  570. {
  571.     if (!strcmp(s, "btree"))
  572.         return (DB_BTREE);
  573.     if (!strcmp(s, "hash"))
  574.         return (DB_HASH);
  575.     if (!strcmp(s, "recno"))
  576.         return (DB_RECNO);
  577.     err("%s: unknown type (use btree, hash or recno)", s);
  578.     /* NOTREACHED */
  579. }
  580.  
  581. void *
  582. setinfo(type, s)
  583.     DBTYPE type;
  584.     char *s;
  585. {
  586.     static BTREEINFO ib;
  587.     static HASHINFO ih;
  588.     static RECNOINFO rh;
  589.     char *eq, *index();
  590.  
  591.     if ((eq = index(s, '=')) == NULL)
  592.         err("%s: illegal structure set statement", s);
  593.     *eq++ = '\0';
  594.     if (!isdigit(*eq))
  595.         err("%s: structure set statement must be a number", s);
  596.         
  597.     switch (type) {
  598.     case DB_BTREE:
  599.         if (!strcmp("flags", s)) {
  600.             ib.flags = atoi(eq);
  601.             return (&ib);
  602.         }
  603.         if (!strcmp("cachesize", s)) {
  604.             ib.cachesize = atoi(eq);
  605.             return (&ib);
  606.         }
  607.         if (!strcmp("maxkeypage", s)) {
  608.             ib.maxkeypage = atoi(eq);
  609.             return (&ib);
  610.         }
  611.         if (!strcmp("minkeypage", s)) {
  612.             ib.minkeypage = atoi(eq);
  613.             return (&ib);
  614.         }
  615.         if (!strcmp("lorder", s)) {
  616.             ib.lorder = atoi(eq);
  617.             return (&ib);
  618.         }
  619.         if (!strcmp("psize", s)) {
  620.             ib.psize = atoi(eq);
  621.             return (&ib);
  622.         }
  623.         break;
  624.     case DB_HASH:
  625.         if (!strcmp("bsize", s)) {
  626.             ih.bsize = atoi(eq);
  627.             return (&ih);
  628.         }
  629.         if (!strcmp("ffactor", s)) {
  630.             ih.ffactor = atoi(eq);
  631.             return (&ih);
  632.         }
  633.         if (!strcmp("nelem", s)) {
  634.             ih.nelem = atoi(eq);
  635.             return (&ih);
  636.         }
  637.         if (!strcmp("cachesize", s)) {
  638.             ih.cachesize = atoi(eq);
  639.             return (&ih);
  640.         }
  641.         if (!strcmp("lorder", s)) {
  642.             ih.lorder = atoi(eq);
  643.             return (&ih);
  644.         }
  645.         break;
  646.     case DB_RECNO:
  647.         if (!strcmp("flags", s)) {
  648.             rh.flags = atoi(eq);
  649.             return (&rh);
  650.         }
  651.         if (!strcmp("cachesize", s)) {
  652.             rh.cachesize = atoi(eq);
  653.             return (&rh);
  654.         }
  655.         if (!strcmp("lorder", s)) {
  656.             rh.lorder = atoi(eq);
  657.             return (&rh);
  658.         }
  659.         if (!strcmp("reclen", s)) {
  660.             rh.reclen = atoi(eq);
  661.             return (&rh);
  662.         }
  663.         if (!strcmp("bval", s)) {
  664.             rh.bval = atoi(eq);
  665.             return (&rh);
  666.         }
  667.         if (!strcmp("psize", s)) {
  668.             rh.psize = atoi(eq);
  669.             return (&rh);
  670.         }
  671.         break;
  672.     }
  673.     err("%s: unknown structure value", s);
  674.     /* NOTREACHED */
  675. }
  676.  
  677. void *
  678. rfile(name, lenp)
  679.     char *name;
  680.     size_t *lenp;
  681. {
  682.     struct stat sb;
  683.     void *p;
  684.     int fd;
  685.     char *np, *index();
  686.  
  687.     for (; isspace(*name); ++name);
  688.     if ((np = index(name, '\n')) != NULL)
  689.         *np = '\0';
  690.     if ((fd = open(name, O_RDONLY, 0)) < 0 ||
  691.         fstat(fd, &sb))
  692.         err("%s: %s\n", name, strerror(errno));
  693. #ifdef NOT_PORTABLE
  694.     if (sb.st_size > (off_t)SIZE_T_MAX)
  695.         err("%s: %s\n", name, strerror(E2BIG));
  696. #endif
  697.     if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
  698.         err("%s", strerror(errno));
  699.     (void)read(fd, p, (int)sb.st_size);
  700.     *lenp = sb.st_size;
  701.     (void)close(fd);
  702.     return (p);
  703. }
  704.  
  705. void *
  706. xmalloc(text, len)
  707.     char *text;
  708.     size_t len;
  709. {
  710.     void *p;
  711.  
  712.     if ((p = (void *)malloc(len)) == NULL)
  713.         err("%s", strerror(errno));
  714.     memmove(p, text, len);
  715.     return (p);
  716. }
  717.  
  718. void
  719. usage()
  720. {
  721.     (void)fprintf(stderr,
  722.         "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
  723.     exit(1);
  724. }
  725.  
  726. #if __STDC__
  727. #include <stdarg.h>
  728. #else
  729. #include <varargs.h>
  730. #endif
  731.  
  732. void
  733. #if __STDC__
  734. err(const char *fmt, ...)
  735. #else
  736. err(fmt, va_alist)
  737.     char *fmt;
  738.         va_dcl
  739. #endif
  740. {
  741.     va_list ap;
  742. #if __STDC__
  743.     va_start(ap, fmt);
  744. #else
  745.     va_start(ap);
  746. #endif
  747.     (void)fprintf(stderr, "dbtest: ");
  748.     (void)vfprintf(stderr, fmt, ap);
  749.     va_end(ap);
  750.     (void)fprintf(stderr, "\n");
  751.     exit(1);
  752.     /* NOTREACHED */
  753. }
  754.